import { assoc, map } from 'ramda';
import uuid from 'uuid/v4';
import {
  escapeString,
  getById,
  prepareDate,
  dayFormat,
  monthFormat,
  yearFormat,
  notify,
  now,
  takeWriteTx,
  commitWriteTx
} from '../database/grakn';
import { BUS_TOPICS } from '../config/conf';
import { index, paginate as elPaginate } from '../database/elasticSearch';

export const findAll = args =>
  elPaginate('stix-domain-entities', assoc('type', 'malware', args));
// paginate('match $m isa Malware', args);

export const search = args =>
  elPaginate('stix-domain-entities', assoc('type', 'malware', args));
/*
  paginate(
    `match $m isa Malware;
    $m has name $name;
    $m has alias $alias;
    { $name contains "${escapeString(args.search)}"; } or 
    { $alias contains "${escapeString(args.search)}"; }`,
    args,
    false
  );
*/

export const findById = malwareId => getById(malwareId);

export const addMalware = async (user, malware) => {
  const wTx = await takeWriteTx();
  const internalId = malware.internal_id
    ? escapeString(malware.internal_id)
    : uuid();
  const malwareIterator = await wTx.tx.query(`insert $malware isa Malware,
    has internal_id "${internalId}",
    has entity_type "malware",
    has stix_id "${
      malware.stix_id ? escapeString(malware.stix_id) : `malware--${uuid()}`
    }",
    has stix_label "",
    has alias "",
    has name "${escapeString(malware.name)}",
    has description "${escapeString(malware.description)}",
    has created ${malware.created ? prepareDate(malware.created) : now()},
    has modified ${malware.modified ? prepareDate(malware.modified) : now()},
    has revoked false,
    has created_at ${now()},
    has created_at_day "${dayFormat(now())}",
    has created_at_month "${monthFormat(now())}",
    has created_at_year "${yearFormat(now())}",         
    has updated_at ${now()};
  `);
  const createMalware = await malwareIterator.next();
  const createdMalwareId = await createMalware.map().get('malware').id;

  if (malware.createdByRef) {
    await wTx.tx.query(
      `match $from id ${createdMalwareId};
      $to has internal_id "${escapeString(malware.createdByRef)}";
      insert (so: $from, creator: $to)
      isa created_by_ref, has internal_id "${uuid()}";`
    );
  }

  if (malware.markingDefinitions) {
    const createMarkingDefinition = markingDefinition =>
      wTx.tx.query(
        `match $from id ${createdMalwareId}; 
        $to has internal_id "${escapeString(markingDefinition)}";
        insert (so: $from, marking: $to) isa object_marking_refs, has internal_id "${uuid()}";`
      );
    const markingDefinitionsPromises = map(
      createMarkingDefinition,
      malware.markingDefinitions
    );
    await Promise.all(markingDefinitionsPromises);
  }

  if (malware.killChainPhases) {
    const createKillChainPhase = killChainPhase =>
      wTx.tx.query(
        `match $from id ${createdMalwareId}; 
        $to has internal_id "${escapeString(killChainPhase)}"; 
        insert (phase_belonging: $from, kill_chain_phase: $to) isa kill_chain_phases, has internal_id "${uuid()}";`
      );
    const killChainPhasesPromises = map(
      createKillChainPhase,
      malware.killChainPhases
    );
    await Promise.all(killChainPhasesPromises);
  }

  await commitWriteTx(wTx);

  return getById(internalId).then(created => {
    index('stix-domain-entities', 'stix_domain_entity', created);
    return notify(BUS_TOPICS.StixDomainEntity.ADDED_TOPIC, created, user);
  });
};
